<!--
 @description 附件上传
 @fileName index.vue
 @author zengqiongying
 @created 2022/11/06 16:09:15
-->
<template>
  <div class="attachment-uploader">
    <div class="file-list">
      <slot v-bind="fileList">
        <ul class="file-list-item">
          <li v-for="f in fileList" :key="getKey(f)">
            <van-progress v-if="f.uploadStatus === 'uploading'" :percentage="f.progress" color="#16BC83" />
            <van-progress v-else-if="f.uploadStatus === 'failed' && !!f.rawFile" :percentage="f.progress" color="#ee0a24" />
            <div class="filename">
              <span class="name">{{ getFileName(f) }}</span>
              <span class="operator">
                <span class="btn" @click.stop="handlerRemove(f)"><svg-icon class="remove" icon-class="cuowuguanbiquxiao" /></span>
                <span v-if="f.uploadStatus === 'failed' && !!f.rawFile" class="btn" @click.stop="handlerReupload(f)">
                  <svg-icon class="reupload" icon-class="shuaxin" />
                </span>
              </span>
            </div>
          </li>
        </ul>
      </slot>
    </div>
    <div v-show="limit<=0 || limit<fileList.length" class="file-input-box" @click.stop="handlerFileClick">
      <slot name="trigger">
        <div class="upload-btn">
          <svg-icon class="plus" icon-class="tianjiaxinjian" />
        </div>
      </slot>
      <input id="file-input" type="file" :accept="accept" :multiple="multiple" style="display: none;" @change="handlerFileChange">
    </div>

    <van-popup
      v-model="popVisible"
      position="bottom"
      round
    >
      <NativeSelectFile
        :visible="popVisible"
        :need-pic-num="limit<=0?1:limit-fileList.length"
        :show-album="showAlbum"
        @success="handlerFileChange"
      />
    </van-popup>
  </div>
</template>
<script>
import { getId } from '@/apis/common'
import NativeSelectFile from './NativeSelectFile'
export default {
  name: 'AttachmentUploader',
  components: { NativeSelectFile },
  props: {
    isCoverOld: {
      type: Boolean,
      default: false
    },
    moduleType: {
      type: String,
      default: ''
    },
    objectId: {
      type: String,
      default: ''
    },
    multiple: {
      type: Boolean,
      default: false
    },
    accept: {
      type: String,
      default: ''
    },
    value: {
      type: Array,
      default: () => []
    },
    limit: {
      type: Number,
      default: 0
    },
    autoGetId: {
      type: Boolean,
      default: false
    },
    showAlbum: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      fileList: [],
      fileEl: null,
      nextId: '',
      token: '',
      popVisible: false
    }
  },
  watch: {
    fileList: {
      handler(v) {
        this.$emit('input', this.fileList.filter(e => e.uploadStatus === 'success').map(e => e.response))
      },
      deep: true
    },
    nextId: {
      handler(v) {
        this.$emit('update:objectId', v)
      }
    }
  },
  mounted() {
    this.fileEl = this.$el.querySelector('#file-input')
  },
  async created() {
    if (this.value.length > 0) {
      this.fileList = this.value.map(e => {
        return this.createFileByResponseObj(e)
      })
    }
    this.getFileList()
    this.autoGetId && this.getId()

    const { token } = await window.nativeHandler()
    this.token = token
  },
  methods: {
    getId() {
      getId().then(res => {
        this.nextId = res.data
      })
    },
    handlerFileClick() {
      this.popVisible = true

      // 仅PC有效
      // this.fileEl.value = null
      // this.fileEl.click()
    },
    handlerFileChange(e) {
      this.popVisible = false
      if (e.target.files.length === 0) {
        return
      }
      for (const file of e.target.files) {
        this.uploader(file)
      }
    },
    getXhr(method, url) {
      const xhr = new XMLHttpRequest()
      xhr.open(method, url)
      xhr.withCredentials = true
      xhr.setRequestHeader('Authorization', this.token)
      xhr.responseType = 'json'
      return xhr
    },
    uploader(file) {
      const isReuploader = !!file.rawFile
      let i
      if (isReuploader) {
        i = this.fileList.indexOf(file)
        file = file.rawFile
      }
      const _file = {
        rawFile: file,
        response: null,
        uploadStatus: 'uploading',
        progress: 0,
        uid: URL.createObjectURL(new Blob([])).toString().split('/').pop()
      }
      const data = new FormData()
      data.append('moduleType', this.moduleType)
      data.append('objectId', this.objectId || this.nextId)
      data.append('isCoverOld', this.isCoverOld ? 1 : 0)
      data.append('file', file)
      isReuploader ? this.fileList.splice(i, 1, _file) : this.fileList.push(_file)
      const xhr = this.getXhr('POST', `${process.env.VUE_APP_BASE_API}/app/v1/attachment/upload`)
      xhr.onreadystatechange = e => {
        if (xhr.readyState === 4) {
          if (xhr.status === 200 && xhr.response.success === 1) {
            this.$set(_file, 'response', xhr.response.data)
            this.$set(_file, 'uploadStatus', 'success')
          } else {
            this.$toast('文件上传失败!')
            this.$set(_file, 'uploadStatus', 'failed')
          }
        }
      }
      xhr.upload.onprogress = e => {
        const progress = Number.parseFloat(((e.loaded / e.total) * 100).toFixed(2))
        this.$set(_file, 'progress', progress)
      }
      xhr.send(data)
    },
    getKey(file) {
      if (file.uid) {
        return file.uid
      }
      if (file.response) {
        return file.response.id
      }
      return URL.createObjectURL(new Blob([])).toString().split('/').pop()
    },
    getFileName(file) {
      if (file.response) {
        return file.response.attachmentName
      }
      if (file.rawFile) {
        return file.rawFile.name
      }
    },
    handlerRemove(file) {
      const i = this.fileList.indexOf(file)
      if (file.uploadStatus === 'failed') {
        i > -1 && this.fileList.splice(i, 1)
        return
      }
      if (!file.response.useId) {
        this.$toast('没有useId无法删除!')
        return
      }
      this.$dialog.confirm({
        title: '提示',
        message: '确认删除?'
      }).then(() => {
        // on confirm
        const xhr = this.getXhr('DELETE', `${process.env.VUE_APP_BASE_API}/app/v1/attachment/deleteByAttachmentUseIds`)
        xhr.setRequestHeader('Content-Type', 'application/json')
        xhr.onreadystatechange = e => {
          if (xhr.readyState === 4) {
            const data = xhr.response
            if (xhr.status === 200 && data.success === 1) {
              i > -1 && this.fileList.splice(i, 1)
              this.$toast('删除成功!')
              // this.getFileList()
            } else {
              this.$toast('删除失败!')
            }
          }
        }
        const data = [file.response.useId]
        xhr.send(JSON.stringify(data))
      }).catch(() => {
        // on cancel
      })
    },
    getFileList() {
      if (!this.objectId) return
      const xhr = this.getXhr('POST', `${process.env.VUE_APP_BASE_API}/app/v1/attachment/upload`)
      xhr.onreadystatechange = e => {
        if (xhr.readyState === 4) {
          const data = xhr.response
          if (xhr.status === 200 && data.success === 1) {
            this.fileList = data.data.records.map(e => {
              return this.createFileByResponseObj(e)
            })
          }
        }
      }
      const data = new FormData()
      data.append('pageFlag', false)
      const filtersRaw = [
        { id: 'objectId', property: 'objectId', value: this.objectId, operator: '=' },
        { id: 'state', property: 'state', value: 1, operator: '=' },
        { id: 'moduleType', property: 'moduleType', value: this.moduleType, operator: '=' }
      ]
      data.append('filtersRaw', JSON.stringify(filtersRaw))
      xhr.send(data)
    },
    handlerReupload(file) {
      this.uploader(file)
    },
    validate(required) {
      return new Promise((resolve, reject) => {
        const t = this.fileList.every(e => e.uploadStatus === 'success')
        if (!t) {
          reject(this.fileList.filter(e => e.uploadStatus !== 'success').map(e => `文件【${this.getFileName(e)}】${e.uploadStatus === 'failed' ? '上传失败' : '正在上传'}`))
        } else if (required && this.fileList.length === 0) {
          reject('')
        } else {
          resolve('')
        }
      })
    },
    createFileByResponseObj(response) {
      return {
        rawFile: null,
        response,
        uploadStatus: 'success',
        progress: 100.00,
        uid: URL.createObjectURL(new Blob([])).toString().split('/').pop()
      }
    }
  }
}
</script>
<style lang="less" scoped>
.attachment-uploader{
  .file-list{
    .file-list-item{
      list-style: none;
      padding: 0;
      margin: 0;
      li{
        padding: 10px;
      }
      .filename{
        display: flex;
        align-items: center;
        .name{
          white-space: nowrap;
          flex: 0 0 auto;
          max-width: calc(100% - 40px);
          overflow: hidden;
          text-overflow: ellipsis;
        }
        .operator{
          margin-left: 5px;
          .btn{
            width: 20px;
            height: 20px;
            display: flex;
            align-items: center;
            justify-content: center;
          }
          &>*{
            cursor: pointer;
            font-size: 16px;
          }
          &>*:hover{
            color: #16bc83;
          }
          .remove{
            color: red;
          }
          .reuploader{
          }
        }
      }
    }
  }
  .file-input-box{

    .upload-btn{
      width: 100%;
      height: 78px;
      border-radius: 8px;
      border: 2px solid #E1EAF9;
      box-sizing: border-box;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .plus{
      font-size: 28px;
      color: #A8B0C5;
      cursor: pointer;
      &:hover{
        color: #16bc83;
      }
    }
  }
}
</style>
